import RampartController from '../rampart'
import { RoomDangerAreaType } from '../rampart/types'

type CreepLike = { id: string; hits: number }

/**
 * tower 控制器
 */
export default class TowerController {
    /**
     * 上一次房间内攻击的敌人
     */
    protected static lastAttackCreepMap: { [roomName: string]: CreepLike } = {}

    /**
     * 上一次更新攻击的时间
     */
    protected static lastUpdateMap: { [roomName: string]: number } = {}

    /**
     * 房间中待维修的建筑 id
     */
    protected static repairList: { [roomName: string]: Set<Id<AnyStructure>> } = {}

    /**
     * 不可实例化
     */
    protected constructor() {
        throw new Error('TowerController 不可被实例化！')
    }

    /**
     * 塔控制器工作
     */
    public static run(room: MyRoom) {
        if (TowerController.autoAttack(room)) return

        TowerController.autoRepair(room)
    }

    /**
     * 塔自动攻击
     */
    public static autoAttack(room: MyRoom) {
        const { lastUpdateMap, lastAttackCreepMap } = TowerController
        let attack = false
        if (!lastUpdateMap[room.name] || lastUpdateMap[room.name] <= 0) {
            lastUpdateMap[room.name] = 10

            const hostiles = room.enemys || []
            if (hostiles.length) {
                lastUpdateMap[room.name] = 0
                hostiles.sort((a, b) =>
                    a.hits / a.hitsMax != b.hits / b.hitsMax
                        ? a.hits / a.hitsMax - b.hits / b.hitsMax
                        : a.hits - b.hits,
                )

                const lastAttack = lastAttackCreepMap[this.name] || { id: '0', hits: 0 }
                const headHostiles = hostiles[0]
                // 上一秒奶不回去的话就攻击
                const lastTickHealAble = headHostiles.id == lastAttack.id && lastAttack.hits <= headHostiles.hits
                if (!lastTickHealAble && headHostiles.hits != headHostiles.hitsMax) {
                    TowerController.allAttack(room.tower, headHostiles)
                    lastAttackCreepMap[this.name] = headHostiles
                    attack = true
                } else if (Game.time % 15 == 7) {
                    const randomHostile = hostiles[_.random(0, hostiles.length - 1)]
                    TowerController.allAttack(room.tower, randomHostile)
                    lastAttackCreepMap[this.name] = randomHostile
                    attack = true
                }
            }
        }

        lastUpdateMap[room.name]--
        return attack
    }

    /**
     * 塔自动维修
     */
    public static autoRepair(room: MyRoom) {
        const { repairList } = TowerController
        if (!repairList[room.name]) repairList[room.name] = new Set()
        const repairSet = repairList[room.name]

        if (repairSet.size) {
            const freeTowers = room.tower.filter((tower) => !tower.isUsed && tower.store['energy'] > 500)
            for (const id of repairSet) {
                if (!freeTowers.length) break

                const target = Game.getObjectById(id)
                if (!target || target.hits > target.hitsMax * 0.8) {
                    repairSet.delete(id)
                    continue
                }

                if (target.hits > 8e3 && (target instanceof StructureRampart || target instanceof StructureWall)) {
                    repairSet.delete(id)
                    continue
                }

                freeTowers.pop()?.repair(target)
            }
        }

        // 等更新建造模块那边有了建筑缓存再维修，避免 find
        if (!room.structures) return

        room.structures.forEach((s) => {
            if (s.hits > s.hitsMax * 0.8) return
            if (s instanceof StructureWall) return
            if (s.hits > 5e3 && s instanceof StructureRampart) return
            // 危险区域的建筑不维修
            if (room.enemys?.length && room.controller.level >= 6) {
                const dangerArea = RampartController.getDangerArea(room)
                const type = dangerArea.get(s.pos.x, s.pos.y)
                if (type === RoomDangerAreaType.inside || type === RoomDangerAreaType.outside) return
            }
            repairSet.add(s.id)
        })
    }

    /**
     * 所有塔集中治疗指定目标
     */
    public static allHeal(towers: StructureTower[], target: AnyCreep) {
        towers?.forEach((tower) => {
            tower.heal(target)
            tower.isUsed = true
        })
    }

    /**
     * 所有塔集中攻击
     */
    public static allAttack(towers: StructureTower[], target: AnyCreep | Structure) {
        towers?.forEach((tower) => {
            if (tower.isUsed) return
            tower.attack(target)
            tower.isUsed = true
        })
    }

    /**
     * 分散攻击
     */
    public static randomAttack(towers: StructureTower[], targets: (AnyCreep | Structure)[]) {
        towers?.forEach((tower, index) => {
            if (tower.isUsed) return
            tower.attack(targets[index % targets.length])
            tower.isUsed = true
        })
    }

    /**
     * 所有爬集中维修
     */
    public static allRepair(towers: StructureTower[], target: Structure) {
        towers?.forEach((tower) => {
            if (tower.isUsed) return
            tower.repair(target)
        })
    }
}

declare global {
    interface StructureTower {
        isUsed?: boolean
    }
}
